home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
Games
/
reve
/
boardstuff.c
next >
Wrap
C/C++ Source or Header
|
1995-05-03
|
21KB
|
806 lines
/*LINTLIBRARY*/
/* @(#)boardstuff.c 1.27 91/11/13
*
* Various board routines used by reve.
*
* Copyright (C) 1990, 1991 - Rich Burridge & Yves Gallot.
* All rights reserved.
*
* Permission is granted to copy this source, for redistribution
* in source form only, provided the news headers in "substantially
* unaltered format" are retained, the introductory messages are not
* removed, and no monies are exchanged.
*
* Permission is also granted to copy this source, without the
* news headers, for the purposes of making an executable copy by
* means of compilation, provided that such copy will not be used
* for the purposes of competition in any othello tournaments, without
* prior permission from the authors.
*
* No responsibility is taken for any errors on inaccuracies inherent
* either to the comments or the code of this program, but if reported
* (see README file), then an attempt will be made to fix them.
*/
#include "reve.h"
#include "color.h"
#include "extern.h"
#include <ctype.h>
#ifdef X11
#include <X11/Xos.h>
#endif /*X11*/
void
animate_move(move)
int move ;
{
int x0, y0, x1, y1, x, y, dx, dy, ctr ;
lock_screen(IS_ON) ;
get_xy(move, &x1, &y1) ;
dx = x1 ;
dy = y1 ;
if (x1 > y1)
{
ctr = dx / 2 ;
x = bborder ;
y = bborder ;
draw_piece(WHITE, x, y, RINV) ;
while (x < x1)
{
#ifndef SYSV
set_timer() ;
#endif /*!SYSV*/
x0 = x ;
y0 = y ;
x += move_delta ;
if ((ctr -= dy) < 0)
{
ctr += dx ;
y += move_delta ;
}
draw_piece(WHITE, x, y, RINV) ;
draw_piece(WHITE, x0, y0, RINV) ;
#ifndef SYSV
nap_upto(1) ;
#endif /*!SYSV*/
}
draw_piece(WHITE, x, y, RINV) ;
}
else
{
ctr = dy / 2 ;
x = bborder ;
y = bborder ;
draw_piece(WHITE, x, y, RINV) ;
while (y < y1)
{
#ifndef SYSV
set_timer() ;
#endif /*!SYSV*/
x0 = x ;
y0 = y ;
y += move_delta ;
if ((ctr -= dx) < 0)
{
ctr += dy ;
x += move_delta ;
}
draw_piece(WHITE, x, y, RINV) ;
draw_piece(WHITE, x0, y0, RINV) ;
#ifndef SYSV
nap_upto(1) ;
#endif /*!SYSV*/
}
draw_piece(WHITE, x, y, RINV) ;
}
lock_screen(IS_OFF) ;
}
/* This routine checks to see if a move can be made for this player.
* If not, various checks are made to see if the game is finished.
* Return value indicates if a move can be made.
*/
int
check(player)
int player ;
{
if ((!count(&board, BLACK)) || (!count(&board, WHITE)) ||
((count(&board, BLACK) + count(&board, WHITE)) == 64))
{
who_wins() ;
last_cmode = cmode ; /* Save previous value in case of undo. */
cmode = GAME_OVER ;
message(PANEL_MES, "***GAME OVER***") ;
return(FALSE) ;
}
if ((move = valid_move(&board, player)) == FALSE)
{
SPRINTF(line, "%s is forced to pass",
(player == BLACK) ? bstone_name : wstone_name) ;
message(PANEL_MES, line) ;
set_turn(OPPONENT(player)) ;
if ((move = valid_move(&board, OPPONENT(player))) == FALSE)
{
who_wins() ;
last_cmode = cmode ;
cmode = GAME_OVER ;
message(PANEL_MES, "***GAME OVER***") ;
}
return(FALSE) ;
}
return(TRUE) ;
}
int
count(board, player) /* Count the number of player pieces on the board. */
BOARD *board ;
int player ;
{
int i, n ;
n = 0 ;
FOR_BOARD(i)
if (board->square[i] == player) n++ ;
return(n) ;
}
void
do_move(player)
int player ;
{
int taken ; /* Number of pieces flipped this go. */
taken = formfliplist(move, player) ;
update_board_image(player, taken) ;
}
void
draw_outline(move, state)
int move ;
enum bltype state ;
{
if (last_outline == -1) return ;
draw_square(move, state, 1) ;
}
void
draw_piece(piece, x, y, op) /* Draw an othello piece on the board. */
int piece, x, y ;
enum optype op ;
{
switch (piece)
{
case BLACK : draw_stencil(W_BOARD, x, y,
2 * pieceXrad, 2 * pieceYrad, op,
B_COLOR(C_BSTONE), P_BLACK, P_BLACK) ;
if (iscolor && op != RINV)
draw_image(W_BOARD, x, y,
2 * pieceXrad, 2 * pieceYrad, P_WHITE) ;
break ;
case WHITE : if (iscolor)
{
draw_stencil(W_BOARD, x, y,
2 * pieceXrad, 2 * pieceYrad, op,
C_WSTONE, P_BLACK, P_BLACK) ;
if (op != RINV)
draw_image(W_BOARD, x, y,
2 * pieceXrad, 2 * pieceYrad, P_WHITE) ;
}
else
draw_stencil(W_BOARD, x, y,
2 * pieceXrad, 2 * pieceYrad, op,
C_WHITE, P_BLACK, P_WHITE) ;
}
}
void
draw_rect(wtype, x1, y1, x2, y2, op, color)
enum win_type wtype ;
int x1, y1, x2, y2, color ;
enum optype op ;
{
draw_line(wtype, x1, y1, x2, y1, op, color) ;
draw_line(wtype, x1, y1, x1, y2, op, color) ;
draw_line(wtype, x2, y1, x2, y2, op, color) ;
draw_line(wtype, x1, y2, x2, y2, op, color) ;
}
void
draw_square(move, state, offset)
int move, offset ;
enum bltype state ;
{
int color, x, y ;
if (state == IS_ON) color = C_BLACK ;
else color = W_COLOR(C_SQUARE) ;
x = (move & 7) * cell_width + bborder ;
y = (move >> 3) * cell_height + bborder ;
draw_rect(W_BOARD, x + offset, y + offset,
x + cell_width - offset, y + cell_height - offset,
RSRC, color) ;
}
void
draw_symbol(image, n, state)
enum image_type image ;
int n ;
enum bltype state ;
{
int color, x, y ;
if (state == IS_OFF) color = W_COLOR(C_SQUARE) ;
else color = C_BLACK ;
x = bborder + ((n & 7) + 1) * cell_width - cell_width / 2 ;
x -= (SWIDTH / 2) ;
y = bborder + ((n >> 3) + 1) * cell_height - cell_height / 2 ;
y -= (SHEIGHT / 2) ;
if (state == IS_OFF)
color_area(W_BOARD, x, y, SWIDTH, SHEIGHT, W_COLOR(C_SQUARE)) ;
else
draw_stencil(W_BOARD, x, y, SWIDTH, SHEIGHT, RSRC, color, image, image) ;
if (state == IS_ON)
draw_image(W_BOARD, x, y, SWIDTH, SHEIGHT, image) ;
}
int
formfliplist(move, player)
int move, player ;
{
int cnt, i, n, old_cnt ;
old_cnt = count(&board, player) ;
FOR_BOARD(i) old_board.square[i] = board.square[i] ;
old_board.moves_left = board.moves_left ;
domove(&old_board, move, &board, player) ;
n = 63 - board.moves_left ;
FOR_BOARD(i) moves[n].square[i] = board.square[i] ;
moves[n].moves_left = board.moves_left ;
moves[n].move = move ;
moves[n].note = note ;
moves[n].player = player ;
moves[n].timeleft = timeleft ;
cnt = count(&board, player) ;
return(cnt - old_cnt - 1) ;
}
void
initboard() /* Initialise the othello board. */
{
static int ivals[4] = { 27, 28, 35, 36 } ;
static int icolors[4] = { WHITE, BLACK, BLACK, WHITE } ;
int i, j , n ;
suggestion = -1 ;
sstate = IS_OFF ;
show_moves = FALSE ;
for (i = 0; i < 64; i++) moves[i].move = -1 ;
for (n = 0; n < 4; n++)
{
FOR_BOARD(i) moves[n].square[i] = FREE ;
for (j = 0; j <= n; j++) moves[n].square[ivals[j]] = icolors[j] ;
moves[n].player = icolors[n] ;
moves[n].move = ivals[n] ;
moves[n].moves_left = 63 - n ;
}
FOR_BOARD(i) old_board.square[i] = board.square[i] = FREE ;
board.square[27] = WHITE ;
board.square[28] = BLACK ;
board.square[35] = BLACK ;
board.square[36] = WHITE ;
board.moves_left = 60 ;
}
void
load_game()
{
/* Read in a game from file, and setup internal variables accordingly.
*
* Notation in the games file is of the format:
* 1, <C-4> - [ remarks field ]
* 2, - <E-3> [ remarks field ]
*
* The move number is the field before the comma. This is just used as a
* consistency check. Next is the black move or the white move (surronded
* by '<' and '>' characters. Obviously only one piece moves per go, and
* the '-' character is used to signify which piece doesn't move (in case
* one player had to miss a turn.
*
* As each position is added, the board is redisplayed, and if the game is
* not over, the next player can commence.
*/
char buf[MAXLINE], col, *lptr, *mptr, row ;
int moveno, n ;
FILE *fp ;
if ((fp = fopen(gamefile, "r")) == NULL)
{
SPRINTF(buf, "Couldn't open game file: %s", gamefile) ;
message(PANEL_MES, buf) ;
return ;
}
moveno = 0 ;
initboard() ;
last_move = -1 ;
paint_board() ;
message(EVAL_MES, "") ;
while (fgets(buf, MAXLINE, fp) != NULL)
{
if (buf[0] == '\n' || buf[0] == '#') continue ;
moveno++ ;
SSCANF(buf, "%d", &n) ;
if (n != moveno || n > 60)
{
SPRINTF(buf, "Load error: incorrect move [%d] on line %d", n, move) ;
message(PANEL_MES, buf) ;
return ;
}
lptr = (char *) index(buf, '<') ;
mptr = (char *) index(buf, '-') ;
if (lptr == NULL || mptr == NULL)
{
SPRINTF(buf, "Load error: missing < or - on line %d", move) ;
message(PANEL_MES, buf) ;
return ;
}
if (lptr < mptr) next_player = BLACK ; /* Black move? */
else next_player = WHITE ;
SSCANF(lptr, "<%c-%c>", &row, &col) ;
if (load_move(row, col) == 0)
{
SPRINTF(buf, "Load error: invalid move <%c-%c> on line %d",
row, col, move) ;
message(PANEL_MES, buf) ;
return ;
}
SPRINTF(buf, "Loaded move %d for %s", moveno,
(next_player == BLACK) ? bstone_name : wstone_name) ;
message(PANEL_MES, buf) ;
}
FCLOSE(fp) ;
set_score() ;
set_turn(OPPONENT(next_player)) ;
cmode = (enum cantype) (OPPONENT(next_player) + 1) ;
next_player = OPPONENT(next_player) ;
if (check(next_player) == TRUE) return ;
cmode = (enum cantype) (OPPONENT(next_player) + 1) ;
next_player = OPPONENT(next_player) ;
if (check(next_player) == FALSE) return ;
if ((next_player == BLACK && cmode == BLACK_START) ||
(next_player == WHITE && cmode == WHITE_START))
{
opponent_move(next_player) ;
next_player = OPPONENT(next_player) ;
}
}
int
load_move(col, row)
int col, row ;
{
int i, x, y ;
if (row < '1' || row > '8') return(0) ;
if (isupper(col)) col = tolower(col) ;
if (col < 'a' || col > 'h') return(0) ;
move = (row - '1') * BOARD_SIZE + (col - 'a') ;
if (legal(move, next_player, &board) == 0) return(0) ;
(void) formfliplist(move, next_player) ;
batch(IS_ON) ;
if (DO_LAST) show_last(last_move, IS_OFF) ;
if (DO_NUMBER) show_number(last_move, 59 - board.moves_left, IS_OFF) ;
FOR_BOARD(i)
if (board.square[i] != old_board.square[i])
{
get_xy(i, &x, &y) ;
draw_piece(next_player, x, y, RSRC) ;
}
if (DO_LAST) show_last(move, IS_ON) ;
if (DO_NUMBER) show_number(move, 60 - board.moves_left, IS_ON) ;
last_move = move ;
batch(IS_OFF) ;
return(1) ;
}
#ifndef SYSV
void
nap_upto(n) /* Sleep upto n microseconds from start of timer. */
int n ;
{
struct timeval ctp ;
struct timezone ctzp ;
long elapsed ; /* Number of microseconds since timer started. */
GETTIMEOFDAY(&ctp, &ctzp) ;
elapsed = ((ctp.tv_usec - tp.tv_usec) +
(ctp.tv_sec - tp.tv_sec) * 1000000L) / 1000 ;
if (elapsed > n) return ;
usleep((unsigned) (n - elapsed)) ;
}
#endif /*!SYSV*/
void
opponent_move(player)
int player ;
{
for (;;)
{
if (processing == FALSE)
{
if (check(player) == TRUE)
{
set_cursor(HOURGLASS) ;
best_cmove = -1 ;
message(EVAL_MES, "") ;
move = moves[63 - board.moves_left].move ;
reset_clock(player) ;
#ifdef REMOTE_PLAYER
if (isremote) write_to_sock(socketfd, move) ;
else
#endif /* REMOTE_PLAYER */
write_to_reve(M_MOVE, board.square, player, level) ;
if (opp_iconise == TRUE) close_reve() ;
return ;
}
else
{
if (cmode != GAME_OVER)
cmode = (enum cantype) ((int) cmode - 1) ;
next_player = OPPONENT(next_player) ;
return ;
}
}
else
{
processing = FALSE ;
update_clock(next_player, TRUE) ;
do_opponent_move(player) ;
reset_clock(OPPONENT(player)) ;
if (check(OPPONENT(player)) == TRUE || cmode == GAME_OVER)
{
next_player = OPPONENT(next_player) ;
if (opp_iconise == TRUE) open_reve() ;
if (opp_bell == TRUE) beep() ;
if (opp_raise == TRUE) raise_reve() ;
return ;
}
}
}
}
void
print_game()
{
char buf[MAXLINE] ;
FILE *fp ;
if ((fp = popen(printcommand, "w")) == NULL)
{
SPRINTF(buf, "Couldn't open printer: %s", printcommand) ;
message(PANEL_MES, buf) ;
return ;
}
save_game_to(fp) ;
PCLOSE(fp) ;
SPRINTF(buf, "Current game printed on %s", printcommand) ;
message(PANEL_MES, buf) ;
}
void
save_game_to(fp)
FILE *fp ;
{
int n ;
for (n = 4; n < 64; n++)
{
if (moves[n].move == -1) break ;
if (moves[n].player == BLACK)
FPRINTF(fp, "%d, <%c-%c> - [ note : %ld ]\n",
n-3, (moves[n].move % 8) + 'a',
(moves[n].move >> 3) + '1', moves[n].note) ;
else
FPRINTF(fp, "%d, - <%c-%c> [ note : %ld ]\n",
n-3, (moves[n].move % 8) + 'a',
(moves[n].move >> 3) + '1', moves[n].note) ;
}
}
void
save_game()
{
/* Save the current game status to file.
*
* The notation in the saved games file is of the format:
* 1, <C-4> - [ note : 12345 ]
* 2, - <E-3> [ note : 0 ]
*
* The move number is the field before the comma. This is just used as a
* consistency check. Next is the black move or the white move (surronded
* by '<' and '>' characters. Obviously only one piece moves per go, and
* the '-' character is used to signify which piece doesn't move (in case
* one player had to miss a turn.
*/
char buf[MAXLINE] ;
FILE *fp ;
if ((fp = fopen(gamefile, "w")) == NULL)
{
SPRINTF(buf, "Couldn't open game file: %s", gamefile) ;
message(PANEL_MES, buf) ;
return ;
}
save_game_to(fp) ;
FCLOSE(fp) ;
SPRINTF(buf, "Current game saved in %s", gamefile) ;
message(PANEL_MES, buf) ;
}
void
set_eval(player, move, note)
int player, move ;
long note ;
{
SPRINTF(line, "%s: <%c-%c> eval : %ld depth: %d",
(player == BLACK) ? bstone_name : wstone_name,
(move & 7) + 'a', (move >> 3) + '1', note, profmax) ;
message(EVAL_MES, line) ;
}
void
set_score()
{
SPRINTF(line, "Stones: %s: %2d %s: %2d",
bstone_name, count(&board, BLACK),
wstone_name, count(&board, WHITE)) ;
message(SCORE_MES, line) ;
}
void
set_turn(player)
int player ;
{
SPRINTF(line, "%s to move", (player == BLACK) ? bstone_name : wstone_name) ;
message(TURN_MES, line) ;
}
#ifndef SYSV
void
set_timer()
{
struct timezone tzp ;
GETTIMEOFDAY(&tp, &tzp) ;
}
#endif /*!SYSV*/
void
show_all(state)
enum bltype state ;
{
int count, i, player ;
batch(IS_ON) ;
if (state == IS_ON)
{
FOR_BOARD(i) s_all.square[i] = FREE ;
FOR_BOARD(i)
if (board.square[i] == FREE &&
(count = legal(i, next_player, &board)) != 0)
{
s_all.square[i] = next_player ;
draw_symbol(S_MOVE, i, IS_ON) ;
show_number(i, count, IS_ON) ;
}
}
else
{
FOR_BOARD(i)
if (s_all.square[i] != FREE)
{
s_all.square[i] = FREE ;
draw_symbol(S_MOVE, i, IS_OFF) ;
}
if (suggestion != -1 && sstate == IS_ON)
{
player = (cmode == WHITE_START) ? WHITE : BLACK ;
do_suggest(player, suggestion, snote, IS_ON) ;
}
}
batch(IS_OFF) ;
show_moves = (int) state ;
}
void
show_best(move, note)
int move ;
long note ;
{
batch(IS_ON) ;
if (move == -1 || DO_BESTMOVE == FALSE) return ;
if (best_cmove != -1)
{
draw_square(best_cmove, IS_OFF, 2) ;
if (DO_NUMBER) show_number(best_cmove, cmove_depth, IS_OFF) ;
}
best_cmove = move ;
cmove_depth = profmax ;
draw_square(best_cmove, IS_ON, 2) ;
if (DO_NUMBER) show_number(best_cmove, cmove_depth, IS_ON) ;
if (SHOW_NOTES) set_eval(next_player, move, note) ;
batch(IS_OFF) ;
}
void
show_last(move, state)
int move ;
enum bltype state ;
{
if (move == -1) return ;
if (board.moves_left < 60) draw_square(move, state, 2) ;
}
void
show_number(move, val, state)
int move, val ;
enum bltype state ;
{
char num[3] ;
int color, strw, x, y ;
if (move == -1) return ;
if (board.square[move] == BLACK)
color = (state == IS_ON) ? C_WHITE : B_COLOR(C_BSTONE) ;
else if (board.square[move] == WHITE)
color = (state == IS_ON) ? C_BLACK : W_COLOR(C_WSTONE) ;
else if (iscolor)
color = (state == IS_ON) ? C_BLACK : C_SQUARE ;
else
color = (state == IS_ON) ? C_BLACK : C_WHITE ;
x = (move & 7) * cell_width + bborder + pieceXmargin ;
y = (move >> 3) * cell_height + bborder + pieceYmargin ;
SPRINTF(num, "%2d", val) ;
strw = get_strwidth(GFONT, num) ;
x = x + ((2 * pieceXrad) - strw) / 2 ;
if (val < 10) x -= 3 ;
y = y + font_heights[(int) GFONT] - 1 +
((2 * pieceYrad) - font_heights[(int) GFONT]) / 2 ;
draw_text(W_BOARD, x, y, GFONT, color, num) ;
}
void
update_board_image(player, taken)
int player, taken ;
{
update_pieces(player, taken) ;
last_move = move ;
if (SHOW_NOTES)
if ((player == BLACK && items[(int) BLACK_PLAYS].value == COMPUTER) ||
(player == WHITE && items[(int) WHITE_PLAYS].value == COMPUTER))
set_eval(player, move, note) ;
}
void
update_pieces(player, taken)
int player, taken ;
{
int flips, i, piece, total_flips, x, y ;
total_flips = (QUICKGAME) ? 2 : 4 ;
if (DO_LAST) show_last(last_move, IS_OFF) ;
if (DO_NUMBER) show_number(last_move, 59 - board.moves_left, IS_OFF) ;
if (show_moves || (invalid == TRUE && SHOW_LEGAL)) show_all(IS_OFF) ;
if (suggestion != -1) draw_symbol(S_SUGGEST, suggestion, IS_OFF) ;
suggestion = -1 ;
sstate = IS_OFF ;
for (flips = 0; flips < total_flips; flips++)
{
batch(IS_ON) ;
FOR_BOARD(i)
{
if (board.square[i] != old_board.square[i])
{
get_xy(i, &x, &y) ;
if (i == move) piece = board.square[i] ;
else
piece = (flips % 2) ? board.square[i] : board.square[i] * -1 ;
draw_piece(piece, x, y, RSRC) ;
}
}
batch(IS_OFF) ;
PAUSE ;
}
if (DO_LAST) show_last(move, IS_ON) ;
if (DO_NUMBER) show_number(move, 60 - board.moves_left, IS_ON) ;
set_score() ;
set_turn(OPPONENT(player)) ;
if (DO_LAST == FALSE && DO_NUMBER == FALSE)
SPRINTF(line, "%s moved at <%c-%c> and took %d %s",
(player == BLACK) ? bstone_name : wstone_name,
(move % 8) + 'a', (move >> 3) + '1',
taken, (taken == 1) ? "stone" : "stones") ;
else
SPRINTF(line, "%s took %d %s",
(player == BLACK) ? bstone_name : wstone_name,
taken, (taken == 1) ? "stone" : "stones") ;
message(PANEL_MES, line) ;
}
void
who_wins()
{
int cs, ps ;
ps = count(&board, WHITE) ;
cs = count(&board, BLACK) ;
if (ps > cs)
{
SPRINTF(line, "%s wins %d-%d", wstone_name, ps, cs) ;
message(SCORE_MES, line) ;
}
else if (ps == cs)
{
SPRINTF(line,"A tie %d-%d", ps, cs) ;
message(SCORE_MES, line) ;
}
else
{
SPRINTF(line, "%s wins %d-%d", bstone_name, cs, ps) ;
message(SCORE_MES, line) ;
}
message(TURN_MES, "") ;
message(EVAL_MES, "") ;
}